package logger

import (
	"fmt"
	"github.com/BurntSushi/toml"
	rotateLogs "github.com/lestrrat-go/file-rotatelogs"
	"github.com/sirupsen/logrus"
	"strings"
	"time"
)

type __logConfig struct {
	Base  base  `toml:"base"`
	Split split `toml:"split"`
}

type base struct {
	LogPath  string `toml:"log_path"`
	LogLevel string `toml:"log_level"`
}

type split struct {
	RotateTime uint `toml:"rotate_time"` //单位分钟
}

var (
	normalLog *logrus.Logger
	sqlLog    *logrus.Logger
	levelMap  = map[string]logrus.Level{
		"trace":   logrus.TraceLevel,
		"debug":   logrus.DebugLevel,
		"info":    logrus.InfoLevel,
		"warn":    logrus.WarnLevel,
		"warning": logrus.WarnLevel,
		"error":   logrus.ErrorLevel,
		"fatal":   logrus.FatalLevel,
		"panic":   logrus.PanicLevel,
	}
	logConfig *__logConfig
	sortMap   = map[string]int{
		"level":       0,
		"time":        1,
		"msg":         2,
		"info":        3,
		"requestUrl":  4,
		"requestData": 5,
		"requestIp":   6,
	}
	err error
)

func (l *__logConfig) parseConfig(configPath string) error {
	_, err = toml.DecodeFile(configPath, l)
	return err
}

func initLogger(logName string) *logrus.Logger {
	currentLogger := logrus.New()
	currentLogger.Formatter = &logrus.JSONFormatter{TimestampFormat: "2006-01-02 15:04:05"}
	currentLogger.Level = levelMap[strings.ToLower(logConfig.Base.LogLevel)]
	writer, _ := rotateLogs.New(
		logName+".%Y%m%d_%H%M%S.log",
		//rotateLogs.WithLinkName(logConfig.Base.LogPath),
		rotateLogs.WithRotationTime(time.Duration(logConfig.Split.RotateTime)*time.Minute),
	)
	currentLogger.SetOutput(writer)
	currentLogger.Formatter = &logrus.TextFormatter{
		TimestampFormat: "2006-01-02 15:04:05",
		SortingFunc: func(stringList []string) {
			for i := len(stringList) - 1; i >= 0; i-- {
				for j := 0; j < i; j++ {
					if sortMap[stringList[j]] > sortMap[stringList[j+1]] {
						stringList[j], stringList[j+1] = stringList[j+1], stringList[j]
					}
				}
			}
		},
	}
	return currentLogger
}

func Init(configPath string) error {
	logConfig = new(__logConfig)
	if err = logConfig.parseConfig(configPath); err != nil {
		return err
	}
	normalLog = initLogger(logConfig.Base.LogPath)
	sqlLog = initLogger(fmt.Sprintf("%s.sql", logConfig.Base.LogPath))
	return nil
}

func TraceLn(args ...interface{}) {
	normalLog.WithFields(getFields(args...)).Traceln(args[0])
}

func DebugLn(args ...interface{}) {
	normalLog.WithFields(getFields(args...)).Debugln(args[0])
}

func InfoLn(args ...interface{}) {
	normalLog.WithFields(getFields(args...)).Infoln(args[0])
}

func WarnLn(args ...interface{}) {
	normalLog.WithFields(getFields(args...)).Warnln(args[0])
}

func WarningLn(args ...interface{}) {
	normalLog.WithFields(getFields(args...)).Warningln(args[0])
}

func ErrorLn(args ...interface{}) {
	normalLog.WithFields(getFields(args...)).Errorln(args[0])
}

func FatalLn(args ...interface{}) {
	normalLog.WithFields(getFields(args...)).Fatalln(args[0])
	normalLog.Exit(1)
}

func PanicLn(args ...interface{}) {
	normalLog.WithFields(getFields(args...)).Panicln(args[0])
}

func getFields(args ...interface{}) logrus.Fields {
	if len(args)%2 != 1 {
		normalLog.WithFields(logrus.Fields{"flag": "write log error,length error", "args": args})
		return nil
	}
	fields := logrus.Fields{}
	args = args[1:]
	for i := 0; i < len(args); i += 2 {
		if value, ok := args[i].(string); !ok {
			normalLog.WithFields(logrus.Fields{"msg": "write log error", "args": args})
			return nil
		} else {
			fields[value] = args[i+1]
		}
	}
	return fields
}

func GetSqlLog() *logrus.Logger {
	return sqlLog
}
